// ##########################################################################
// #                                                                        #
// #                              CLOUDCOMPARE                              #
// #                                                                        #
// #  This program is free software; you can redistribute it and/or modify  #
// #  it under the terms of the GNU General Public License as published by  #
// #  the Free Software Foundation; version 2 or later of the License.      #
// #                                                                        #
// #  This program is distributed in the hope that it will be useful,       #
// #  but WITHOUT ANY WARRANTY; without even the implied warranty of        #
// #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the          #
// #  GNU General Public License for more details.                          #
// #                                                                        #
// #          COPYRIGHT: EDF R&D / TELECOM ParisTech (ENST-TSI)             #
// #                                                                        #
// ##########################################################################

#ifndef CC_SENSOR_HEADER
#define CC_SENSOR_HEADER

// Local
#include "ccIndexedTransformationBuffer.h"

//! Sensor types
enum CC_SENSOR_TYPE
{
	UNKNOWN_SENSOR,
	GROUND_BASED_LIDAR,
};

//! Generic sensor interface
/** New sensor framework now relies on separate positions (stored
    in a buffer) as generated by a GPS/IMU. This way, sensor objects
    only contains intrinsic parameters. They are also associated
    to a 'rigid transformation' (e.g. a rigid mechanical link between
    the sensor 'optical' center and the GPS/IMU center position).
**/
class QCC_DB_LIB_API ccSensor : public ccHObject
{
  public:
	//! Default constructor
	ccSensor(const QString& name);

	//! Copy constructor
	ccSensor(const ccSensor& sensor);

	//! Destructor
	~ccSensor() override;

	// inherited from ccHObject
	CC_CLASS_ENUM getClassID() const override
	{
		return CC_TYPES::SENSOR;
	}
	bool isSerializable() const override
	{
		return true;
	}

	//! Returns the sensor type
	/** Should be re-implemented by sub-classes
	    \return the sensor type
	**/
	virtual CC_SENSOR_TYPE getType() const
	{
		return UNKNOWN_SENSOR;
	}

	//! Returns the "visibility type" of a point
	/** Precise definition of point's visibility can be found in Daniel Girardeau-Montaut's
	    PhD manuscript (Chapter 2, section 2-3-3). In fact it can be anything, assuming that
	    a point that is not POINT_VISIBLE won't be compared during a point-to-cloud distance
	    computation process.
	    \deprecated This method is deprecated and should be ignored.
	    \param P a 3D point
	    \return the visibility of the point
	**/
	virtual inline unsigned char checkVisibility(const CCVector3& P) const
	{
		return CCCoreLib::POINT_VISIBLE;
	}

	//! Returns associated positions
	ccIndexedTransformationBuffer* getPositions()
	{
		return m_posBuffer;
	}
	//! Returns associated positions
	const ccIndexedTransformationBuffer* getPositions() const
	{
		return m_posBuffer;
	}

	//! Sets associated positions
	void setPositions(ccIndexedTransformationBuffer* positions)
	{
		m_posBuffer = positions;
	}

	//! Adds a new position (shortcut)
	/** \warning may be slow as this method may sort the positions
	    after each call (if the new index is lower than the last one pushed)
	**/
	bool addPosition(ccGLMatrix& trans, double index);

	//! Returns the absolute transformation between the world and the "optical" center (shortcut)
	/** Absolute transformation corresponds to the rigid transformation
	    multiplied by the associated transformation interpolated at the given index.
	**/
	bool getAbsoluteTransformation(ccIndexedTransformation& trans, double index) const;

	//! Gets currently active absolute transformation
	bool getActiveAbsoluteTransformation(ccIndexedTransformation& trans) const;

	//! Gets currently active absolute position
	bool getActiveAbsoluteCenter(CCVector3& vec) const;

	//! Gets currently active rotation matrix (without translation)
	bool getActiveAbsoluteRotation(ccGLMatrix& rotation) const;

	//! Sets the rigid transformation between this sensor and its associated positions
	/** Rigid transformation goes from the sensor position(s) to the sensor "optical" center.
	 **/
	virtual void setRigidTransformation(const ccGLMatrix& mat)
	{
		m_rigidTransformation = mat;
	}

	//! Returns the rigid transformation between this sensor and its associated positions
	virtual ccGLMatrix& getRigidTransformation()
	{
		return m_rigidTransformation;
	}

	//! Returns the rigid transformation between this sensor and its associated positions (const version)
	virtual const ccGLMatrix& getRigidTransformation() const
	{
		return m_rigidTransformation;
	}

	//! Gets index boundaries (shortcut)
	void getIndexBounds(double& minIndex, double& maxIndex) const;

	//! Sets currently active index (displayed position, etc.)
	double getActiveIndex() const
	{
		return m_activeIndex;
	}

	//! Sets currently active index (displayed position, etc.)
	void setActiveIndex(double index)
	{
		m_activeIndex = index;
	}

	//! Sets the sensor graphic representation scale
	void setGraphicScale(PointCoordinateType scale)
	{
		m_scale = scale;
	}

	//! Returns the sensor graphic representation scale
	PointCoordinateType getGraphicScale() const
	{
		return m_scale;
	}

	//! Apply sensor 'viewport' to a 3D view
	/** \param win 3D view to which to apply the sensor viewport (or the associated 'display' if 0)
	    \return success
	**/
	virtual bool applyViewport(ccGenericGLDisplay* win = nullptr) const;

	// inherited from ccHObject
	void applyGLTransformation(const ccGLMatrix& trans) override;

  protected:
	// inherited from ccHObject
	bool  toFile_MeOnly(QFile& out, short dataVersion) const override;
	bool  fromFile_MeOnly(QFile& in, short dataVersion, int flags, LoadedIDMap& oldToNewIDMap) override;
	short minimumFileVersion_MeOnly() const override;

	//! Positions buffer (optional)
	ccIndexedTransformationBuffer* m_posBuffer;

	//! Rigid transformation between this sensor and its associated positions
	/** The transformation goes from the sensor position(s) to the sensor "optical" center.
	 **/
	ccGLMatrix m_rigidTransformation;

	//! Active index (for displayed position, etc.)
	double m_activeIndex;

	//! Color of the sensor
	/** Default color is green.
	 **/
	ccColor::Rgb m_color;

	//! Sensor graphic representation scale
	PointCoordinateType m_scale;
};

#endif // CC_SENSOR_HEADER
